
package com.jf.cloud.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.product.util.ProductLangUtil;
import com.jf.cloud.common.cache.constant.CacheNames;
import com.jf.cloud.common.cache.util.RedisUtil;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageAdapter;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.product.constant.AttrType;
import com.jf.cloud.common.product.dto.AttrLangDTO;
import com.jf.cloud.common.product.vo.AttrVO;
import com.jf.cloud.common.product.vo.CategoryVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.product.dto.AttrDTO;
import com.jf.cloud.product.mapper.AttrMapper;
import com.jf.cloud.product.model.Attr;
import com.jf.cloud.product.model.AttrLang;
import com.jf.cloud.product.model.AttrValue;
import com.jf.cloud.product.service.*;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 属性信息
 *
 * @author zz
 * @date 2020-10-28 15:27:23
 */
@Service
public class AttrServiceImpl implements AttrService {

    @Autowired
    private AttrMapper attrMapper;
    @Autowired
    private AttrLangService attrLangService;
    @Autowired
    private AttrValueLangService attrValueLangService;
    @Autowired
    private AttrCategoryService attrCategoryService;
    @Autowired
    private AttrValueService attrValueService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SpuAttrValueService spuAttrValueService;
    @Autowired
    private MapperFacade mapperFacade;

    @Override
    public PageVO<AttrVO> page(PageDTO pageDTO, AttrDTO attrDTO) {
        PageVO<AttrVO> pageVO = new PageVO<>();
        attrDTO.setShopId(AuthUserContext.get().getTenantId());
        pageVO.setList(attrMapper.list(new PageAdapter(pageDTO), attrDTO));
        ProductLangUtil.attrList(pageVO.getList());
        pageVO.setTotal(attrMapper.countAttr(attrDTO));
        pageVO.setPages(PageUtil.getPages(pageVO.getTotal(), pageDTO.getPageSize()));
        return pageVO;
    }

    @Override
    public AttrVO getByAttrId(Long attrId) {
        AttrVO attrVO = attrMapper.getByAttrId(attrId);
        attrVO.setSysType(AuthUserContext.get().getSysType());
        if (Objects.isNull(attrVO)) {
            throw new LuckException("属性不存在或已删除");
        }
        if (Objects.equals(attrVO.getAttrType(), AttrType.BASIC.value())) {
            attrVO.setCategories(attrCategoryService.listByAttrId(attrId));
            categoryService.getPathNames(attrVO.getCategories());
        }
        return attrVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(AttrDTO attrDTO) {
        Attr attr = mapperFacade.map(attrDTO, Attr.class);
        attr.setAttrValues(mapperFacade.mapAsList(attrDTO.getAttrValues(), AttrValue.class));
        attr.setShopId(AuthUserContext.get().getTenantId());

        if (Objects.equals(AttrType.SALES.value(), attr.getAttrType())) {
            hasNameRepeated(attrDTO.getAttrLangList(), attr.getShopId(), null);
        }
        attrMapper.save(attr);
        // 属性语言
        checkAttrLangData(attrDTO.getAttrLangList());
        attrLangService.save(mapperFacade.mapAsList(attrDTO.getAttrLangList(), AttrLang.class), attr.getAttrId());
        // 保存属性值
        attrValueService.save(attrDTO.getAttrValues(), attr.getAttrId());
        // 基本属性关联分类
        if (Objects.equals(AttrType.BASIC.value(), attr.getAttrType())) {
            // 保存属性分类关联信息
            attrCategoryService.save(attr.getAttrId(), attrDTO.getCategoryIds());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(AttrDTO attrDTO) {
        Integer sysType = AuthUserContext.get().getSysType();
        attrDTO.setSysType(sysType);
        Attr attr = mapperFacade.map(attrDTO, Attr.class);
        AttrVO dbAttr = attrMapper.getByAttrId(attr.getAttrId());
        if (Objects.equals(AttrType.SALES.value(), attr.getAttrType())) {
            hasNameRepeated(attrDTO.getAttrLangList(), attr.getShopId(), attr.getAttrId());
        }
        checkAttrLangData(attrDTO.getAttrLangList());

        // 更新属性信息
        attrMapper.update(attr);
        // 更新属性语言表
        for (AttrLangDTO name : attrDTO.getAttrLangList()) {
            name.setAttrId(attr.getAttrId());
        }
        attrLangService.update(mapperFacade.mapAsList(attrDTO.getAttrLangList(), AttrLang.class), dbAttr);
        // 更新属性值
        attrValueService.update(attrDTO, dbAttr);
        // 更新属性分类关联信息
        if (Objects.equals(dbAttr.getAttrType(), AttrType.BASIC.value())) {
            List<Long> ids = attrCategoryService.update(attr.getAttrId(), attrDTO.getCategoryIds());
            // 清除取消关联的分类的数据
            spuAttrValueService.deleteByCategoryIds(attr.getAttrId(), ids);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long attrId) {
        attrValueService.deleteByAttrId(attrId);
        attrLangService.deleteById(attrId);
        attrMapper.deleteById(attrId);
    }

    @Override
    @Cacheable(cacheNames = CacheNames.ATTRS_BY_CATEGORY_KEY, key = "#categoryId")
    public List<AttrVO> getAttrsByCategoryIdAndAttrType(Long categoryId) {
        return  attrMapper.getAttrsByCategoryIdAndAttrType(AttrType.BASIC.value(), categoryId, null, SysTypeEnum.PLATFORM.value());
    }

    @Override
    public List<Long> getAttrOfCategoryIdByAttrId(Long attrId) {
        AttrVO attr = attrMapper.getByAttrId(attrId);
        if (Objects.isNull(attr)) {
            throw new LuckException("属性不存在");
        }
        if (CollUtil.isEmpty(attr.getCategories())) {
            return new ArrayList<>();
        }
        return attr.getCategories().stream().map(CategoryVO::getCategoryId).collect(Collectors.toList());
    }

    @Override
    public void removeAttrByCategoryId(List<Long> categoryIds) {
        if (CollUtil.isEmpty(categoryIds)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        for (Long categoryId : categoryIds) {
            keys.add(CacheNames.ATTRS_BY_CATEGORY_KEY + CacheNames.UNION + categoryId);
        }
        RedisUtil.deleteBatch(keys);
    }

    @Override
    public List<AttrVO> getShopAttrs(Long shopId, Integer sysType) {
        return attrMapper.getAttrsByCategoryIdAndAttrType(AttrType.SALES.value(), null, shopId, sysType);
    }

    /**
     * 判断属性名是否已存在
     * @param attrLangList
     * @param shopId
     * @param attrId
     */
    private void hasNameRepeated(List<AttrLangDTO> attrLangList, Long shopId, Long attrId) {
        List<AttrLang> dbAttrLangList = attrMapper.countAttrName(attrLangList, shopId, attrId);
        if (CollUtil.isEmpty(dbAttrLangList)) {
            return;
        }
        Set<String> nameSet = dbAttrLangList.stream().map(AttrLang::getName).collect(Collectors.toSet());
        throw new LuckException("规格名" + nameSet + "已存在");
    }

    /**
     * 检验属性国际化信息是否正确
     * @param attrLangList 属性国际化信息
     */
    private void checkAttrLangData(List<AttrLangDTO> attrLangList) {
        if (CollUtil.isEmpty(attrLangList)) {
            throw new LuckException("规格名不能为空");
        }
        boolean correct = false;
        Iterator<AttrLangDTO> iterator = attrLangList.iterator();
        while (iterator.hasNext()) {
            AttrLangDTO attrLangDTO = iterator.next();
            if (StrUtil.isBlank(attrLangDTO.getName())) {
                iterator.remove();
                continue;
            }
            if (Objects.equals(attrLangDTO.getLang(), Constant.DEFAULT_LANG)) {
                correct = true;
            }
        }
        if (CollUtil.isEmpty(attrLangList) || !correct) {
            throw new LuckException(ResponseEnum.DATA_ERROR);
        }
    }
}
